<?php
/**
 * 公共类
 * @user: 1874
 */
namespace app\common\controller;
use think\facade\Cache;
use think\facade\Config;
use think\facade\Db;

class Common {
    private const TOKEN_KEY = "USER_TOKEN"; // token缓存key值
    private static $desKey;  //des 秘钥
    private static $desIv;   //des 向量
    /**
     * 构造函数
     */
    public function __construct(){
        // des 配置
        $desConfig = Config::get("app.des_config");
        self::$desKey = $desConfig["desKey"];
        self::$desIv = $desConfig["desIv"];
    }
    /**
     * 获取前X名排名
     * @param array $params 查询参数
     * @return array;
     */
    public static function getTopRanking(array $params): array {
        $condition = [
            "table" => $params["table"] ?? "tb_user",
            "fields" => $params["fields"] ?? "*",
            "where" => $params["where"] ?? "us_status = 1",
            "order" => $params["order"] ?? "us_score Desc",
            "num" => $params["num"] ?? 100,
            "alias" => $params["alias"] ?? "rank",
        ];
        return Db::query("SELECT * FROM (
                SELECT {$condition["fields"]},(@rank:=@rank+1) AS {$condition["alias"]} 
                FROM {$condition["table"]}, (SELECT (@rank:=0)) b 
                WHERE {$condition["where"]} ORDER BY {$condition["order"]}
            ) c LIMIT {$condition["num"]}"
        );
    }
    /**
     * 获取当前用户排名
     * @param array $params 查询参数
     * @return array;
     */
    public static function getCurrentRanking(array $params): array {
        $condition = [
            "table" => $params["table"] ?? "tb_user",
            "fields" => $params["fields"] ?? "*",
            "where" => $params["where"] ?? "us_status = 1",
            "order" => $params["order"] ?? "us_score Desc",
            "extWhere" => $params["extWhere"] ?? "us_id = 1",
            "alias" => $params["alias"] ?? "rank",
        ];
        return Db::query("SELECT * FROM (
                SELECT {$condition["fields"]},(@rank:=@rank+1) AS {$condition["alias"]} 
                FROM {$condition["table"]}, (SELECT (@rank:=0)) b 
                WHERE {$condition["where"]} ORDER BY {$condition["order"]}
            ) c WHERE {$condition["extWhere"]}"
        );
    }
    /**
     * 获取微信用户信息
     * @param string $code
     * @return object
     */
    public static function getWechatUserInfo(string $code): array {
        if($code) {
            $wechat = new Wechat();
            // 获取临时凭证
            $token = $wechat->getTemporaryAccessToken($code, 1);
            if (!empty($token["errcode"])) {
                return resData($token, "获取凭证失败", ERR_CODE);
            }
            // 临时凭证access_token获取授权后用户资料
            $userInfo = $wechat->getOauthUserinfo($token["access_token"], $token["openid"]);
            if(!empty($userInfo["errcode"])) {
                return resData($userInfo, "获取用户信息失败", ERR_CODE);
            }
            return resData($userInfo);
        }
        return resData(null, "未接收code", ERR_CODE);
    }
    /**
     * 获取微信签名, 用于分享朋友圈、朋友等
     * @return array
     */
    public static function getWechatSignature(string $url = null): ?array {
        $wechat = new Wechat();
        // 是否有缓存
        if(Cache::has("signature")){
            $signature = Cache::get("signature");
        }else{
            // 获取accessToken
            $accessToken = $wechat->getAccessToken();
            // 获取js api_ticket签名凭证
            $signature = $wechat->getJsApiTicket($accessToken);
            // 保存7100秒
            Cache::set("signature", $signature, 7100);
        }
        // 随机字符串
        $randStr = getRandStr(20);
        // 加密签名
        $data["appId"] = Config::get("app.wechat_config.app_id");
        $data["timestamp"] = time();
        $data["nonceStr"] = $randStr;
        $data["signature"] = $wechat->getSignature($signature, $randStr, $url);
        return $data ?? null;
    }
    /**
     * 生成token
     */
    public static function setEncryptToken(int $uid): string {
        $des = new DES(self::$desKey, "DES-CBC", DES::OUTPUT_BASE64, self::$desIv);
        $str = setJsonArray(["time" => time(), "uid" => $uid, "uniqid" => uniqid()]);
        return $des->encrypt($str);
    }
    /**
     * 解密token
     */
    public static function getDecryptToken(string $token): array {
        $des = new DES(self::$desKey, "DES-CBC", DES::OUTPUT_BASE64, self::$desIv);
        return json_decode($des->decrypt($token), true);
    }
    /**
     * 使用id设置token并返回
     * @desc Array[uid => token]
     */
    public static function useIdSetToken(int $id, $tokenKey = self::TOKEN_KEY): string {
        // token数组
        $tokenArr = [];
        // 如果有缓存则赋值给tokenArr
        if(Cache::has($tokenKey)) $tokenArr = Cache::get($tokenKey);
        // 生成token
        $token = self::setEncryptToken($id);
        // 替换或新增对应uid的token值
        $tokenArr[$id] = $token;
        // 存储到缓存中
        Cache::set($tokenKey, $tokenArr);
        return $token;
    }
    /**
     * 使用token获取用户id，并判断请求token是否一致
     */
    public static function useTokenGetUserId(string $token, $tokenKey = self::TOKEN_KEY): array {
        // 如果有缓存则返回数组，没有则返回空数组
        $tokenArr = Cache::has($tokenKey) ? Cache::get($tokenKey) : [];
        // 通过DES解密，获取uid找到对应的缓存token，对比请求token是否一致
        $user = self::getDecryptToken($token);
        if ($user && $tokenArr[$user["uid"]] == $token) {
            return resData($user["uid"]);
        }
        return resData([], "登录已过期", EXPIRE_CODE);
    }
}